package javax.core.storage.spring.s3;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.core.common.utils.StringUtils;
import java.io.*;
import java.util.Objects;
import java.util.zip.GZIPInputStream;

@Component
public class AWSClientS3 {
    @Value("${filestorage.accesskey}")
    private String accesskey;
    @Value("${filestorage.secretkey}")
    private String secretkey;

    static AmazonS3 s3;

    @PostConstruct
	public void init() {
		BasicAWSCredentials awsCreds = new BasicAWSCredentials(accesskey, secretkey);
		s3 = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(awsCreds))
				.withRegion(Regions.CN_NORTHWEST_1).build();
	}

	public boolean createBucket(String bucketName) {
		try {
			s3.createBucket(bucketName);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	public void listObjects(String bucketName) {
		System.out.println("Listing objects of " + bucketName);
		ObjectListing objectListing = s3.listObjects(bucketName);
		int objectNum = 0;
		for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
			System.out.println(" - " + objectSummary.getKey());
			objectNum++;
		}
		System.out.println("total " + objectNum + " object(s).");
	}

	private static boolean isObjectExit(String bucketName, String key) {
		int len = key.length();
		ObjectListing objectListing = s3.listObjects(bucketName);
		String s = new String();
		for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
			s = objectSummary.getKey();
			int slen = s.length();
			if (len == slen) {
				int i;
				for (i = 0; i < len; i++)
					if (s.charAt(i) != key.charAt(i))
						break;
				if (i == len)
					return true;
			}
		}
		return false;
	}

	public void savePublicObject(String bucketName, String pathFileName, File file) throws IOException {
		if (checkFileExists(bucketName, pathFileName, file)) {
			return;
		}
		if (pathFileName.startsWith("/")) {
			pathFileName = pathFileName.substring(1);
		}
		file.deleteOnExit();

		s3.putObject(bucketName, pathFileName, file);
	}

	public void savePublicObject(String bucketName, String pathFileName, InputStream fileInputStream) throws IOException {
		if (checkFileExists(bucketName, pathFileName, fileInputStream)) {
			return;
		}
		if (pathFileName.startsWith("/")) {
			pathFileName = pathFileName.substring(1);
		}
		s3.putObject(new PutObjectRequest(bucketName, pathFileName, fileInputStream, null)
				.withCannedAcl(CannedAccessControlList.PublicRead));
	}

	private boolean checkFileExists(String bucketName, String pathFileName, Object fileInput) {
		if (StringUtils.isEmpty(bucketName) || StringUtils.isEmpty(pathFileName) || Objects.isNull(fileInput)) {
			return false;
		}
		if (pathFileName.startsWith("/")) {
			pathFileName = pathFileName.substring(1);
		}
		return isObjectExit(bucketName, pathFileName);
	}

	private void showContentOfAnObject(String bucketName, String key) {
		S3Object object = s3.getObject(new GetObjectRequest(bucketName, key));
		InputStream input = object.getObjectContent();
		BufferedReader reader = new BufferedReader(new InputStreamReader(input));
		try {
			while (true) {
				String line = reader.readLine();
				if (line == null)
					break;
				System.out.println("    " + line);
			}
			System.out.println();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void showContentOfAnGzipObject(String bucketName, String key) {
		try {
			S3Object object = s3.getObject(new GetObjectRequest(bucketName, key));
			InputStream input = new GZIPInputStream(object.getObjectContent());
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));

			while (true) {
				String line = reader.readLine();
				if (line == null)
					break;
				System.out.println("    " + line);
			}
			System.out.println();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void listBuckets() {
		System.out.println("Listing buckets");
		int bucketNum = 0;
		for (Bucket bucket : s3.listBuckets()) {
			System.out.println(" - " + bucket.getName());
			bucketNum++;
		}
		System.out.println("total " + bucketNum + " bucket(s).");
	}

	private static void deleteBucket(String bucketName) {
		if (s3.doesBucketExistV2(bucketName) == false) {
			System.out.println(bucketName + " does not exists!");
			return;
		}
		System.out.println("deleting " + bucketName + " ...");
		ObjectListing objectListing = s3.listObjects(bucketName);
		for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
			String key = objectSummary.getKey();
			s3.deleteObject(bucketName, key);
		}
		s3.deleteBucket(bucketName);
		System.out.println(bucketName + " has been deleted!");
	}

	private static void deleteObjectsWithPrefix(String bucketName, String prefix) {
		if (s3.doesBucketExistV2(bucketName) == false) {
			System.out.println(bucketName + " does not exists!");
			return;
		}
		System.out.println("deleting " + prefix + "* in " + bucketName + " ...");
		int pre_len = prefix.length();
		ObjectListing objectListing = s3.listObjects(bucketName);
		for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
			String key = objectSummary.getKey();
			int len = key.length();
			if (len < pre_len)
				continue;
			int i;
			for (i = 0; i < pre_len; i++)
				if (key.charAt(i) != prefix.charAt(i))
					break;
			if (i < pre_len)
				continue;
			s3.deleteObject(bucketName, key);
		}
		System.out.println("All " + prefix + "* deleted!");
	}

	private static void createFolder(String bucketName, String folderName) {
		// Create metadata for my folder & set content-length to 0
		ObjectMetadata metadata = new ObjectMetadata();
		metadata.setContentLength(0);
		// Create empty content
		InputStream emptyContent = new ByteArrayInputStream(new byte[0]);
		// Create a PutObjectRequest passing the foldername suffixed by /
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, folderName + "/", emptyContent, metadata);
		// Send request to S3 to create folder
		s3.putObject(putObjectRequest);
	}
}
